const crypto = require('crypto');
const https = require('https');
const http = require('http');

class LhzxHttpClient {
    constructor() {
        // 单例模式（可选）
    }

    /**
     * 发送POST请求到云翼信API
     * @param {string} jsonRequestString - JSON格式的请求字符串
     * @param {string} restServiceURL - 服务地址
     * @returns {Promise<string>} - 返回JSON格式的响应
     */
    async sendPostRequest(jsonRequestString, restServiceURL) {
        return new Promise((resolve, reject) => {
            try {
                const url = new URL(restServiceURL);
                const isHttps = url.protocol === 'https:';
                const httpModule = isHttps ? https : http;
                
                const postData = jsonRequestString;
                
                const options = {
                    hostname: url.hostname,
                    port: url.port || (isHttps ? 443 : 80),
                    path: url.pathname + url.search,
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json;charset=UTF-8',
                        'Content-Length': Buffer.byteLength(postData, 'utf8')
                    }
                };

                const req = httpModule.request(options, (res) => {
                    let data = '';
                    
                    res.setEncoding('utf8');
                    res.on('data', (chunk) => {
                        data += chunk;
                    });
                    
                    res.on('end', () => {
                        if (res.statusCode !== 200) {
                            reject(new Error(`Failed : HTTP error code : ${res.statusCode}`));
                        } else {
                            resolve(data);
                        }
                    });
                });
                
                req.on('error', (err) => {
                    reject(err);
                });
                
                // 发送POST数据
                req.write(postData);
                req.end();
                
            } catch (error) {
                reject(error);
            }
        });
    }

    /**
     * MD5加密后Base64编码（按照云翼信协议规范）
     * @param {string} str - 要加密的字符串
     * @returns {string} - Base64编码的MD5哈希值
     */
    encoderByMd5(str) {
        try {
            const md5Hash = crypto.createHash('md5');
            md5Hash.update(str, 'utf8');
            const md5Result = md5Hash.digest();
            return Buffer.from(md5Result).toString('base64');
        } catch (error) {
            console.error('MD5编码错误:', error);
            return '';
        }
    }

    /**
     * 格式化时间戳（按照云翼信协议规范）
     * @param {Date} date - 日期对象
     * @returns {string} - 格式化的时间戳 yyyyMMddhhmmsszzz（17位）
     */
    formatTimestamp(date = new Date()) {
        const year = date.getFullYear();
        const month = String(date.getMonth() + 1).padStart(2, '0');
        const day = String(date.getDate()).padStart(2, '0');
        const hours = String(date.getHours()).padStart(2, '0');
        const minutes = String(date.getMinutes()).padStart(2, '0');
        const seconds = String(date.getSeconds()).padStart(2, '0');
        const milliseconds = String(date.getMilliseconds()).padStart(3, '0');
        
        return `${year}${month}${day}${hours}${minutes}${seconds}${milliseconds}`;
    }

    /**
     * 生成流水号（streamingNo）
     * @param {string} siid - 系统标识
     * @param {string} timeStamp - 时间戳
     * @returns {string} - 流水号
     */
    generateStreamingNo(siid, timeStamp) {
        return siid + timeStamp;
    }

    /**
     * 计算认证码（按照云翼信协议规范）
     * authenticator = BASE64(MD5(timeStamp+transactionID+streamingNo+接口密钥))
     * @param {string} timeStamp - 时间戳
     * @param {string} transactionID - 事务号
     * @param {string} streamingNo - 流水号
     * @param {string} secretKey - 接口密钥
     * @returns {string} - 认证码
     */
    calculateAuthenticator(timeStamp, transactionID, streamingNo, secretKey) {
        const authString = timeStamp + transactionID + streamingNo + secretKey;
        return this.encoderByMd5(authString);
    }

    /**
     * 发送短信（按照云翼信协议规范）
     * @param {Object} config - 配置对象
     * @param {string} config.siid - 客户编号（SI的唯一标识）
     * @param {string} config.user - HTTP账号
     * @param {string} config.secretKey - 接口密钥
     * @param {string} config.mobile - 手机号码（群发用英文逗号分隔，最多50个）
     * @param {string} config.content - 短信内容
     * @param {string} config.extcode - 扩展码（可选）
     * @param {string} config.url - 请求地址（可选，默认使用云翼信调试地址）
     * @returns {Promise<Object>} - 响应结果
     */
    async sendSMS(config) {
        const { 
            siid, 
            user, 
            secretKey, 
            mobile, 
            content, 
            extcode = "", 
            url = "https://yyx.saas.189.cn:8070/jt3netsmsservicehttp/httpservices/capService"
        } = config;
        
        // 生成时间戳和事务ID
        const currentTime = new Date();
        const timeStamp = this.formatTimestamp(currentTime);
        const transactionID = timeStamp; // 事务号与时间戳相同
        const streamingNo = this.generateStreamingNo(siid, timeStamp);
        
        // 计算认证码
        const authenticator = this.calculateAuthenticator(timeStamp, transactionID, streamingNo, secretKey);
        
        // 构造请求JSON（按照云翼信协议规范）
        const requestData = {
            siid: siid,
            user: user,
            streamingNo: streamingNo,
            timeStamp: timeStamp,
            transactionID: transactionID,
            authenticator: authenticator,
            mobile: mobile,
            extcode: extcode,
            content: content
        };
        
        const jsonRequest = JSON.stringify(requestData);
        
        console.log('=== 云翼信短信发送请求 ===');
        console.log('请求URL:', url);
        console.log('请求参数:', JSON.stringify(requestData, null, 2));
        console.log('认证字符串:', timeStamp + transactionID + streamingNo + secretKey);
        console.log('认证码:', authenticator);
        console.log();
        
        try {
            const response = await this.sendPostRequest(jsonRequest, url);
            console.log('原始响应:', response);
            
            // 解析响应
            const responseObj = JSON.parse(response);
            console.log('解析后响应:', responseObj);
            
            // 返回码说明
            this.explainRetCode(responseObj.retCode);
            
            return responseObj;
        } catch (error) {
            console.error('发送请求失败:', error.message);
            throw error;
        }
    }

    /**
     * 解释返回码含义
     * @param {string} retCode - 返回码
     */
    explainRetCode(retCode) {
        const codeMap = {
            '0000': '调用成功',
            '0101': '请求包格式不正确',
            '0200': '数据库异常',
            '0401': '流水码重复',
            '0402': '订购关系不存在',
            '0403': '认证失败（IP地址不合法或秘钥不正确）',
            '0404': '黑名单',
            '0408': '非法关键字',
            '0501': '非法请求参数',
            '0801': '短信速率上限',
            '0806': '秘钥不存在或者加密算法有问题',
            '0901': '其他异常'
        };
        
        const message = codeMap[retCode] || '未知返回码';
        console.log(`返回码 ${retCode}: ${message}`);
        
        if (retCode !== '0000') {
            console.log('❌ 短信发送失败');
        } else {
            console.log('✅ 短信发送成功');
        }
    }

    /**
     * 验证配置参数
     * @param {Object} config - 配置对象
     * @returns {boolean} - 验证结果
     */
    validateConfig(config) {
        const required = ['siid', 'user', 'secretKey', 'mobile', 'content'];
        const missing = required.filter(key => !config[key]);
        
        if (missing.length > 0) {
            console.error('缺少必要参数:', missing.join(', '));
            return false;
        }
        
        // 验证手机号格式
        const mobilePattern = /^1[3-9]\d{9}$/;
        const mobiles = config.mobile.split(',');
        
        if (mobiles.length > 50) {
            console.error('手机号数量不能超过50个');
            return false;
        }
        
        for (const mobile of mobiles) {
            if (!mobilePattern.test(mobile.trim())) {
                console.error('手机号格式不正确:', mobile);
                return false;
            }
        }
        
        return true;
    }
}

// 使用示例和测试
async function main() {
    const client = new LhzxHttpClient();
    
    // 配置参数 - 请根据实际情况修改
    const config = {
        siid: "",                    // 客户编号（由云翼信平台分配）
        user: "",                    // HTTP账号（由云翼信平台分配）
        secretKey: "",               // 接口密钥（由云翼信平台分配）
        mobile: "13800138000",       // 手机号码（群发用英文逗号分隔，最多50个）
        content: "【测试】云翼信测试短信", // 短信内容
        extcode: "123"               // 扩展码（可选）
    };
    
    // 验证配置
    if (!client.validateConfig(config)) {
        console.error('配置验证失败，请检查参数');
        return;
    }
    
    try {
        const result = await client.sendSMS(config);
        console.log('\n=== 发送结果 ===');
        console.log('事务号:', result.transactionID);
        console.log('返回码:', result.retCode);
        console.log('返回消息:', result.retMsg);
    } catch (error) {
        console.error('程序执行错误:', error.message);
    }
}

// 导出类和运行主函数
module.exports = LhzxHttpClient;

// 如果直接运行此文件，则执行main函数
if (require.main === module) {
    main();
} 